﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

namespace Base.ModuleBase.Attachs
{
    public class ItemsControlAttach
    {
        #region 横向滚动

        public static bool GetIsHorizontalRoll(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsHorizontalRollProperty);
        }

        public static void SetIsHorizontalRoll(DependencyObject obj, bool value)
        {
            obj.SetValue(IsHorizontalRollProperty, value);
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsHorizontalRollProperty =
            DependencyProperty.RegisterAttached("IsHorizontalRoll", typeof(bool), typeof(ItemsControlAttach), new PropertyMetadata(false, OnRollBottomCommandPropertyChanged));

        #endregion

        #region 自动滚动到选中项

        /// <summary>
        /// Returns the value of the AutoScrollToCurrentItemProperty
        /// </summary>
        /// <param name="obj">The dependency-object whichs value should be returned</param>
        /// <returns>The value of the given property</returns>
        public static bool GetAutoScrollToCurrentItem(DependencyObject obj)
        {
            return (bool)obj.GetValue(AutoScrollToCurrentItemProperty);
        }

        /// <summary>
        /// Sets the value of the AutoScrollToCurrentItemProperty
        /// </summary>
        /// <param name="obj">The dependency-object whichs value should be set</param>
        /// <param name="value">The value which should be assigned to the AutoScrollToCurrentItemProperty</param>
        public static void SetAutoScrollToCurrentItem(DependencyObject obj, bool value)
        {
            obj.SetValue(AutoScrollToCurrentItemProperty, value);
        }

        /// <summary>
        /// The automatic scroll to current item property
        /// </summary>
        public static readonly DependencyProperty AutoScrollToCurrentItemProperty = DependencyProperty.RegisterAttached("AutoScrollToCurrentItem",
            typeof(bool), typeof(ItemsControlAttach), new UIPropertyMetadata(default(bool), OnAutoScrollToCurrentItemChanged));

        /// <summary>
        /// This method will be called when the AutoScrollToCurrentItem
        /// property was changed
        /// </summary>
        /// <param name="sender">The sender (the ListBox)</param>
        /// <param name="e">Some additional information</param>
        public static void OnAutoScrollToCurrentItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            switch (sender)
            {
                case ListBox list:
                    {
                        if (list is null || list.Items is null)
                            return;

                        var enable = (bool)e.NewValue;
                        if (enable)
                            list.SelectionChanged += ListBox_SelectionChanged;
                        else
                            list.SelectionChanged -= ListBox_SelectionChanged;
                        break;
                    }
                case DataGrid dataGrid:
                    {
                        if (dataGrid is null || dataGrid.Items is null)
                            return;

                        var enable = (bool)e.NewValue;
                        if (enable)
                            dataGrid.SelectionChanged += DataGrid_SelectionChanged;
                        else
                            dataGrid.SelectionChanged -= DataGrid_SelectionChanged;
                        break;
                    }
            }
        }

        private static void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var listBox = (DataGrid)sender;
            if (listBox != null && listBox.SelectedItem != null)
            {
                listBox.ScrollIntoView(listBox.SelectedItem);
            }
        }

        private static void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var listBox = (ListBox)sender;
            if (listBox != null && listBox.SelectedItem != null)
            {
                listBox.ScrollIntoView(listBox.SelectedItem);
            }
        }

        #endregion

        #region 触底刷新
        public static ICommand GetRollBottomCommand(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(RollBottomCommandProperty);
        }

        public static void SetRollBottomCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(RollBottomCommandProperty, value);
        }
        /// <summary>
        /// The roll bottom command property
        /// </summary>
        public static readonly DependencyProperty RollBottomCommandProperty =
            DependencyProperty.RegisterAttached("RollBottomCommand", typeof(ICommand), typeof(ItemsControlAttach), new PropertyMetadata(null, OnRollBottomCommandPropertyChanged));

        /// <summary>
        /// Handles the <see cref="E:RollBottomCommandPropertyChanged" /> event.
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.</param>
        private static void OnRollBottomCommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ItemsControl itemsControl)
            {
                itemsControl.PreviewMouseWheel -= OnPreviewMouseWheel;
                itemsControl.PreviewMouseWheel += OnPreviewMouseWheel;
            }
        }

        private static void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (sender is ItemsControl itemsControl)
            {
                var scrollViewer = itemsControl.GetChildObject<ScrollViewer>();
                if (scrollViewer != null)
                {
                    bool isScroll;
                    if (GetIsHorizontalRoll(itemsControl))
                    {
                        scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset - e.Delta);
                        isScroll = scrollViewer.IsHorizontalScrollBarAtButtom();
                    }
                    else
                    {
                        isScroll = scrollViewer.IsVerticalScrollBarAtButtom();
                    }
                    if (isScroll)
                    {
                        var tempCommand = GetRollBottomCommand(itemsControl);
                        tempCommand?.Execute(scrollViewer);
                    }
                }
            }
        }
        #endregion
    }
}
